package yxy.apple.nio;

import java.net.InetSocketAddress;

import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

public abstract class Handler extends ChannelDuplexHandler {
	private ChannelHandlerContext context = null;
	private InetSocketAddress remoteAddress = null;
	private InetSocketAddress localAddress = null;
	private long birthday = 0;
	// public final String uuid = IDGenerator.nextUUID();

	@Override
	@Deprecated
	public void channelRegistered(ChannelHandlerContext context) throws Exception {
		context.fireChannelRegistered();
		this.open();
	}

	protected void open() throws Exception {
		this.opened();
	}

	/**
	 * 通道打开时回调（尚未接通）
	 */
	protected abstract void opened() throws Exception;

	@Override
	@Deprecated
	public void channelActive(ChannelHandlerContext context) throws Exception {
		context.fireChannelActive();
		this.birthday = System.currentTimeMillis();
		this.context = context;
		this.remoteAddress = (InetSocketAddress) context.channel().remoteAddress();
		this.localAddress = (InetSocketAddress) context.channel().localAddress();
		this.active();
	}

	protected void active() throws Exception {
		this.actived();
	}

	/**
	 * 通道活跃（连接已通）时回调
	 */
	protected abstract void actived() throws Exception;

	@Override
	@Deprecated
	public void channelInactive(ChannelHandlerContext context) throws Exception {
		this.inactive();
		context.fireChannelInactive();
	}

	protected void inactive() throws Exception {
		this.inactived();
	}

	/**
	 * 通道失活（连接断开）时回调
	 */
	protected abstract void inactived() throws Exception;

	@Override
	@Deprecated
	public void channelUnregistered(ChannelHandlerContext context) throws Exception {
		this.close();
		this.context = null;
		context.fireChannelUnregistered();
	}

	protected void close() throws Exception {
		this.closed();
	}

	/**
	 * 通道关闭时回调
	 */
	protected abstract void closed() throws Exception;

	@Override
	public void userEventTriggered(ChannelHandlerContext context, Object event) throws Exception {
		context.fireUserEventTriggered(event);
		this.trigger(event);
	}

	protected void trigger(Object event) throws Exception {
		this.triggered(event);
	}

	/**
	 * 触发事件时回调
	 * 
	 * @param event
	 */
	protected abstract void triggered(Object event) throws Exception;

	@Override
	@Deprecated
	public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
		this.caught(cause);
	}

	public void caught(Throwable cause) {
		this.thrown(cause);
	}

	/**
	 * 抛出异常时回调
	 * 
	 * @param exception
	 */
	protected abstract void thrown(Throwable cause);

	@Override
	@Deprecated
	public void channelRead(ChannelHandlerContext context, Object message) throws Exception {
		this.receive(message);
	}

	/**
	 * 接收到消息时回调
	 * 
	 * @param message
	 * @throws NairobiException
	 */
	public abstract void receive(Object message) throws Exception;

	public ChannelHandlerContext context() {
		return context;
	}

	public void disconnect() {
		if (this.context != null && this.context().channel() != null) {
			this.context.channel().close();
		}
	}

	/**
	 * 远端地址
	 * 
	 * @return
	 */
	public InetSocketAddress remoteAddress() {
		return remoteAddress;
	}

	/**
	 * 本地地址
	 * 
	 * @return
	 */
	public InetSocketAddress localAddress() {
		return localAddress;
	}

	/**
	 * 发送消息并立即写出
	 * 
	 * @param message
	 * @throws NairobiException
	 */
	public void send(Object message) throws Exception {
		this.send(message, null, true);
	}

	/**
	 * 发送消息
	 * 
	 * @param message 消息实例
	 * @param promise 发送结果监听器
	 * @param flush   是否理解写出缓存
	 * @throws NairobiException
	 */
	public void send(Object message, ChannelPromise promise, boolean flush) throws Exception {
		this.send(message, promise, flush, null);
	}

	/**
	 * 发送消息
	 * 
	 * @param message
	 * @param promise
	 * @param flush
	 * @param listener
	 * @throws Exception
	 */
	public void send(Object message, ChannelPromise promise, boolean flush, GenericFutureListener<? extends Future<? super Void>> listener)
			throws Exception {
		try {
			if (this.context != null && this.context.channel() != null && this.context.channel().isActive()) {
				ChannelFuture future = promise == null ? context.write(message) : context.write(message, promise);
				if (future != null && listener != null) {
					future.addListener(listener);
				}
				if (flush) {
					context.flush();
				}
			} else {
				throw new ChannelException("Channel is not available!");
			}
		} catch (Exception e) {
			throw e;
		}
	}

	public long age() {
		return System.currentTimeMillis() - this.birthday;
	}

	public long birthday() {
		return this.birthday;
	}

	public boolean alive() {
		if (this.context != null && this.context.channel() != null && this.context.channel().isActive()) {
			return true;
		} else {
			return false;
		}
	}

}
